package com.cat.tiger.jdbcproxy;

import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.*;

import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

public class LoadBlanceJdbcTemplate extends JdbcTemplate {

    private boolean hasRootDataSource = false;
    @javax.annotation.Resource
    private BasicDataSource dataSourceSlave; // 增加本jdbcTempLate的健壮性
    private JdbcTemplatePool jdbcTemplatePool;

    public BasicDataSource getDataSourceSlave() {
        return dataSourceSlave;
    }

    public void setDataSourceSlave(BasicDataSource dataSourceSlave) {
        this.dataSourceSlave = dataSourceSlave;
    }

    public LoadBlanceJdbcTemplate() {
        jdbcTemplatePool = new JdbcTemplatePool();
        super.setDataSource(new BasicDataSource());
    }

    public long[] getCallCount() {
        return jdbcTemplatePool.getCallCount();
    }

    @Override
    public DataSource getDataSource() {
        return chooseJdbc().getDataSource();
    }

    @Override
    public <T> T query(PreparedStatementCreator psc, final PreparedStatementSetter pss,
                       final ResultSetExtractor<T> rse) throws DataAccessException {
        return chooseJdbc().query(psc, pss, rse);
    }

    @Override
    public <T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse)
            throws DataAccessException {
        return chooseJdbc().query(psc, rse);
    }

    @Override
    public void query(PreparedStatementCreator psc, RowCallbackHandler rch)
            throws DataAccessException {
        chooseJdbc().query(psc, rch);
    }

    @Override
    public <T> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper)
            throws DataAccessException {
        return chooseJdbc().query(psc, rowMapper);
    }

    @Override
    public <T> T query(String sql, Object[] args, int[] argTypes, ResultSetExtractor<T> rse)
            throws DataAccessException {
        return chooseJdbc().query(sql, args, argTypes, rse);
    }

    @Override
    public void query(String sql, Object[] args, int[] argTypes, RowCallbackHandler rch)
            throws DataAccessException {
        chooseJdbc().query(sql, args, argTypes, rch);
    }

    @Override
    public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)
            throws DataAccessException {
        return chooseJdbc().query(sql, args, argTypes, rowMapper);
    }

    @Override
    public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse)
            throws DataAccessException {
        return chooseJdbc().query(sql, args, rse);
    }

    @Override
    public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {
        chooseJdbc().query(sql, args, rch);
    }

    @Override
    public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper)
            throws DataAccessException {
        return chooseJdbc().query(sql, args, rowMapper);
    }

    @Override
    public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse)
            throws DataAccessException {
        return chooseJdbc().query(sql, pss, rse);
    }

    // -------------------------------------------------------------------------
    // Methods dealing with prepared statements
    // -------------------------------------------------------------------------

    @Override
    public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch)
            throws DataAccessException {
        chooseJdbc().query(sql, pss, rch);
    }

    @Override
    public <T> List<T> query(String sql, PreparedStatementSetter pss, RowMapper<T> rowMapper)
            throws DataAccessException {
        return chooseJdbc().query(sql, pss, rowMapper);
    }

    @Override
    public <T> T query(final String sql, final ResultSetExtractor<T> rse)
            throws DataAccessException {
        return chooseJdbc().query(sql, rse);
    }

    @Override
    public <T> T query(String sql, ResultSetExtractor<T> rse, Object... args)
            throws DataAccessException {
        return chooseJdbc().query(sql, rse, args);
    }

    @Override
    public void query(String sql, RowCallbackHandler rch) throws DataAccessException {
        chooseJdbc().query(sql, rch);
    }

    @Override
    public void query(String sql, RowCallbackHandler rch, Object... args)
            throws DataAccessException {
        chooseJdbc().query(sql, rch, args);
    }

    @Override
    public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return chooseJdbc().query(sql, rowMapper);
    }

    @Override
    public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args)
            throws DataAccessException {
        return chooseJdbc().query(sql, rowMapper, args);
    }

    @Override
    public int queryForInt(String sql) {
        return chooseJdbc().queryForInt(sql);
    }

    @Override
    public int queryForInt(String sql, Object... args) throws DataAccessException {
        return chooseJdbc().queryForInt(sql, args);
    }

    @Override
    public int queryForInt(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        return chooseJdbc().queryForInt(sql, args, argTypes);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql) throws DataAccessException {
        return chooseJdbc().queryForList(sql);
    }

    @Override
    public <T> List<T> queryForList(String sql, Class<T> elementType) throws DataAccessException {
        return chooseJdbc().queryForList(sql, elementType);
    }

    @Override
    public <T> List<T> queryForList(String sql, Class<T> elementType, Object... args)
            throws DataAccessException {
        return chooseJdbc().queryForList(sql, elementType, args);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql, Object... args)
            throws DataAccessException {
        return chooseJdbc().queryForList(sql, args);
    }

    @Override
    public <T> List<T> queryForList(String sql, Object[] args, Class<T> elementType)
            throws DataAccessException {
        return chooseJdbc().queryForList(sql, args, elementType);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql, Object[] args, int[] argTypes)
            throws DataAccessException {
        return chooseJdbc().queryForList(sql, args, argTypes);
    }

    @Override
    public <T> List<T> queryForList(String sql, Object[] args, int[] argTypes, Class<T> elementType)
            throws DataAccessException {
        return chooseJdbc().queryForList(sql, args, argTypes, elementType);
    }

    @Override
    public long queryForLong(String sql) throws DataAccessException {
        return chooseJdbc().queryForLong(sql);
    }

    @Override
    public long queryForLong(String sql, Object... args) throws DataAccessException {
        return chooseJdbc().queryForLong(sql, args);
    }

    @Override
    public long queryForLong(String sql, Object[] args, int[] argTypes) throws DataAccessException {
        return chooseJdbc().queryForLong(sql, args, argTypes);
    }

    @Override
    public Map<String, Object> queryForMap(String sql) throws DataAccessException {
        return chooseJdbc().queryForMap(sql);
    }

    @Override
    public Map<String, Object> queryForMap(String sql, Object... args) throws DataAccessException {
        return chooseJdbc().queryForMap(sql, args);
    }

    @Override
    public Map<String, Object> queryForMap(String sql, Object[] args, int[] argTypes)
            throws DataAccessException {
        return chooseJdbc().queryForMap(sql, args, argTypes);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {
        return chooseJdbc().queryForObject(sql, requiredType);
    }

    @Override
    public <T> T queryForObject(String sql, Class<T> requiredType, Object... args)
            throws DataAccessException {
        return chooseJdbc().queryForObject(sql, requiredType, args);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType)
            throws DataAccessException {
        return chooseJdbc().queryForObject(sql, args, requiredType);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, int[] argTypes, Class<T> requiredType)
            throws DataAccessException {

        return chooseJdbc().queryForObject(sql, args, argTypes, requiredType);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)
            throws DataAccessException {

        return chooseJdbc().queryForObject(sql, args, argTypes, rowMapper);
    }

    @Override
    public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper)
            throws DataAccessException {
        return chooseJdbc().queryForObject(sql, args, rowMapper);
    }

    @Override
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
        return chooseJdbc().queryForObject(sql, rowMapper);
    }

    @Override
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args)
            throws DataAccessException {
        return chooseJdbc().queryForObject(sql, rowMapper, args);
    }

    private JdbcTemplate chooseJdbc() {
        if (dataSourceSlave != null && !hasRootDataSource) {
            super.setDataSource(dataSourceSlave);
            hasRootDataSource = true;
        }
        return jdbcTemplatePool.chooseJdbc();
    }

}
